import axios, { AxiosInstance } from 'axios'
import { LoadingManager } from '../loadingManager'
import { CancelStrategy } from './cancelStrategy'
import { setupResponseInterceptor } from './responseInterceptor'
import { hosts } from '../../config/hosts'

/**
 * 基础服务类，封装了通用的HTTP请求逻辑
 */
export class BaseService {
  // 加载状态管理器实例
  private loadingManager = LoadingManager.getInstance()
  // 请求取消策略实例
  private cancelStrategy = new CancelStrategy()
  // Axios实例
  private axiosInstance: AxiosInstance

  constructor() {
    // 初始化Axios实例
    this.axiosInstance = axios.create({
      baseURL: hosts.baseUrl, // 使用配置中的API基础URL
      timeout: 10000, // 请求超时时间10秒
      headers: {
        'Content-Type': 'application/json' // 默认请求头
      }
    })
    // 设置响应拦截器
    setupResponseInterceptor(this.axiosInstance)
  }

  /**
   * 执行HTTP请求的通用方法
   * @param params 请求参数
   * @param data 请求体数据
   * @returns 返回响应数据
   */
  protected async executeMethod<TParams = any, TResponse = any>(params?: TParams, data?: any): Promise<TResponse> {
    // 获取调用栈信息以确定调用方法名
    const stack = new Error().stack || ''
    const caller = stack.split('\n')[2] || ''
    const methodName = caller.match(/\.(\w+)\s/)?.[1]
    if (!methodName) throw new Error('无法确定调用的方法名称')

    // 通过反射获取方法元数据
    const method = Reflect.getMetadata('httpMethod', this.constructor.prototype, methodName)
    const url = Reflect.getMetadata('url', this.constructor.prototype, methodName)
    const cancelable = Reflect.getMetadata('cancelable', this.constructor.prototype, methodName)
    const noToken = Reflect.getMetadata('noToken', this.constructor.prototype, methodName)
    const retry = Reflect.getMetadata('retry', this.constructor.prototype, methodName)

    // 处理URL中的路径参数
    const finalUrl = url.replace(
      /\{(\w+)\}/g,
      (_: string, key: string) => (params as Record<string, string>)?.[key] || ''
    )

    // 构建请求配置
    const config: any = {
      method,
      url: finalUrl,
      headers: {}
    }

    // 根据请求方法处理参数
    if (method === 'GET') {
      config.params = params
    } else {
      config.data = params || data
    }

    // 如果需要token，添加到请求头
    if (!noToken) {
      config.headers['Authorization'] = `Bearer ${localStorage.getItem('token')}`
    }

    // 处理可取消请求
    this.cancelStrategy.handleCancelableRequest(config, cancelable, method, finalUrl)
    // 显示加载状态
    this.loadingManager.show()

    try {
      let response
      // 重试机制
      for (let i = 0; i <= retry; i++) {
        try {
          response = await this.axiosInstance(config)
          break
        } catch (error: any) {
          // 达到重试次数或非服务器错误时抛出异常
          if (i === retry || !error.response || error.response.status < 500) {
            throw error
          }
        }
      }
      // 请求成功处理
      this.loadingManager.hide()
      this.cancelStrategy.removeRequest(method, finalUrl)
      return response as TResponse
    } catch (error: any) {
      // 请求失败处理
      this.loadingManager.hide()
      this.cancelStrategy.removeRequest(method, finalUrl)
      throw error
    }
  }
}
